package com.block.merchant.service.impl;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.block.account.enums.AccountTypeEnum;
import com.block.account.enums.ActionTypeEnum;
import com.block.account.model.dto.ChangeAmountDTO;
import com.block.account.service.IAccountHandleService;
import com.block.common.constant.RedisKeyConstant;
import com.block.common.enums.InfoTypeEnum;
import com.block.common.exception.NotifyExceptionService;
import com.block.common.model.dto.CountInfoDTO;
import com.block.common.model.dto.MemberBaseInfoDTO;
import com.block.common.service.IChannelCommonService;
import com.block.common.service.IMemberCommonService;
import com.block.common.service.LogFactory;
import com.block.common.util.ApplicationContextUtil;
import com.block.db.entity.DataMatchOrderItem;
import com.block.db.entity.MemberSourceInfo;
import com.block.db.entity.MerchantBaseInfo;
import com.block.db.entity.MerchantTaskInfo;
import com.block.db.mapper.MemberSourceInfoMapper;
import com.block.db.mapper.MerchantBaseInfoMapper;
import com.block.merchant.factory.InfoTypeFactory;
import com.block.common.model.dto.FlowCountDTO;
import com.block.merchant.model.dto.MerchantOrderDTO;
import com.block.merchant.model.dto.PushCountDTO;
import com.block.merchant.model.dto.PushSettleDTO;
import com.block.merchant.model.result.DataPushResult;
import com.block.merchant.model.result.MatchMerchantInfo;
import com.block.merchant.service.IMerchantBaseInfoService;
import com.block.merchant.service.IMerchantDataPushFlowCountInfoService;
import com.block.merchant.service.IMerchantPushCountInfoService;
import com.block.merchant.service.IMerchantTaskInfoService;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 商户基本信息 服务实现类
 * </p>
 *
 * @author
 * @since 2023-08-12
 */
@Service
public class MerchantBaseInfoServiceImpl extends ServiceImpl<MerchantBaseInfoMapper, MerchantBaseInfo> implements IMerchantBaseInfoService {

    private static final Logger log = LogFactory.getMerchantLog();

    @Resource
    MemberSourceInfoMapper memberSourceInfoMapper;
    @Resource
    MerchantBaseInfoMapper merchantBaseInfoMapper;
    @Autowired
    IAccountHandleService accountHandleService;
    @Autowired
    IChannelCommonService channelCommonService;
    @Autowired
    IMerchantPushCountInfoService merchantPushCountInfoService;
    @Autowired
    IMerchantTaskInfoService merchantTaskInfoService;
    @Autowired
    NotifyExceptionService notifyExceptionService;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    IMerchantDataPushFlowCountInfoService merchantDataPushFlowCountInfoService;
    @Autowired
    IMemberCommonService memberCommonService;


    /**
     * 商户信息匹配
     * <p>
     * 获取到单个机构的匹配结果
     */
    @Override
    public MatchMerchantInfo matchWithMerchant(MerchantOrderDTO merchantOrderDTO, MemberSourceInfo memberSourceInfo) throws Exception {

        MerchantBaseInfo merchantBaseInfo = this.getById(merchantOrderDTO.getInfoId());
        merchantOrderDTO.setInfoType(merchantBaseInfo.getInfoType());
        merchantOrderDTO.setDeptId(merchantBaseInfo.getDeptId());
        merchantOrderDTO.setShowPostion(merchantBaseInfo.getShowPosition());

        MatchMerchantInfo matchMerchantInfo = InfoTypeFactory.getService(merchantBaseInfo.getInfoType())
                .matchWithMerchant(merchantBaseInfo, merchantOrderDTO, memberSourceInfo);

        matchMerchantInfo.setSinglePushFlag(merchantBaseInfo.getSinglePushFlag());
        return matchMerchantInfo;
    }

    /**
     * 商户信息匹配
     * <p>
     * 获取到单个机构的匹配结果
     */
    @Override
    public MatchMerchantInfo sourceCheckWithMerchant(MerchantOrderDTO merchantOrderDTO, MemberSourceInfo memberSourceInfo) throws Exception {

        try {
            MerchantBaseInfo merchantBaseInfo = this.getById(merchantOrderDTO.getInfoId());
            merchantOrderDTO.setInfoType(merchantBaseInfo.getInfoType());
            merchantOrderDTO.setInfoName(merchantBaseInfo.getInfoName());
            merchantOrderDTO.setDeptId(merchantBaseInfo.getDeptId());
            merchantOrderDTO.setShowPostion(merchantBaseInfo.getShowPosition());

            // 执行具体的逻辑
            MatchMerchantInfo matchMerchantInfo = InfoTypeFactory.getService(merchantBaseInfo.getInfoType())
                    .sourceCheckWithMerchant(merchantBaseInfo, merchantOrderDTO, memberSourceInfo);

            matchMerchantInfo.setInfoId(merchantBaseInfo.getId());
            matchMerchantInfo.setInfoType(merchantBaseInfo.getInfoType());
            matchMerchantInfo.setInfoName(merchantBaseInfo.getInfoName());
            matchMerchantInfo.setShowPosition(merchantBaseInfo.getShowPosition());

            matchMerchantInfo.setTaskId(merchantOrderDTO.getTaskId());
            matchMerchantInfo.setProfitAmount(merchantOrderDTO.getPriceAmount());

            return matchMerchantInfo;
        } catch (Exception exception) {
            exception.printStackTrace();
            notifyExceptionService.notifyNoticeInfo("SOURCE_CHECK_ERROR", "线索撞库异常", JSON.toJSONString(merchantOrderDTO), exception);
            throw exception;
        }
    }

    /**
     * 商户信息推送
     * 余额信息更新
     * 以及账户历史记录
     * 。0.。。
     */
    @Override
    public DataPushResult pushToMerchant(DataMatchOrderItem dataMatchOrderItem) throws Exception {

        try {
            MerchantBaseInfo merchantBaseInfo = this.getById(dataMatchOrderItem.getInfoId());
            MemberSourceInfo memberSourceInfo = memberSourceInfoMapper.selectById(dataMatchOrderItem.getUid());

            MerchantOrderDTO merchantOrderDTO = new MerchantOrderDTO();
            merchantOrderDTO.setInfoId(dataMatchOrderItem.getInfoId());
            merchantOrderDTO.setInfoType(dataMatchOrderItem.getInfoType());
            merchantOrderDTO.setTaskId(dataMatchOrderItem.getTaskId());

            merchantOrderDTO.setOrderId(dataMatchOrderItem.getOrderId());
            merchantOrderDTO.setOrderItemId(dataMatchOrderItem.getId());

            String orderItemId = dataMatchOrderItem.getPushId();
            if (ObjectUtil.isNotEmpty(orderItemId)) {
                merchantOrderDTO.setPushPoolId(Long.valueOf(orderItemId));
            }

            merchantOrderDTO.setDeptId(merchantBaseInfo.getDeptId());
            merchantOrderDTO.setPriceAmount(dataMatchOrderItem.getProfitAmount());
            // 需要查询任务信息
            MerchantTaskInfo merchantTaskInfo = merchantTaskInfoService.getById(dataMatchOrderItem.getTaskId());
            merchantOrderDTO.setCostAmount(merchantTaskInfo.getCostAmount());
            merchantOrderDTO.setPayAmount(merchantTaskInfo.getPayAmount());

            DataPushResult dataPushResult = InfoTypeFactory.getService(merchantBaseInfo.getInfoType())
                    .pushToMerchant(merchantOrderDTO, merchantBaseInfo, memberSourceInfo);

            // 异步执行结算数据
            ThreadUtil.execAsync(new Runnable() {
                @Override
                public void run() {
                    // 结算相关参数
                    PushSettleDTO pushSettleDTO = new PushSettleDTO();

                    pushSettleDTO.setPushFlag(dataPushResult.isPushSuccess());
                    pushSettleDTO.setSettleFlag(dataPushResult.isSettleFlag());
                    pushSettleDTO.setSettleAmount(merchantOrderDTO.getPriceAmount());

                    pushSettleDTO.setChannelCode(memberSourceInfo.getChannelCode());

                    pushSettleDTO.setInfoId(merchantBaseInfo.getId());
                    pushSettleDTO.setInfoName(merchantBaseInfo.getInfoName());
                    pushSettleDTO.setInfoType(merchantBaseInfo.getInfoType());
                    pushSettleDTO.setTaskId(merchantOrderDTO.getTaskId());

                    pushSettleDTO.setOrderId(String.valueOf(dataMatchOrderItem.getOrderId()));
                    pushSettleDTO.setOrderItemId(String.valueOf(dataMatchOrderItem.getId()));
                    pushSettleDTO.setPushPoolId(dataPushResult.getPushOrderId());
                    ApplicationContextUtil.getBean(IMerchantBaseInfoService.class).handlePushToData(pushSettleDTO, memberSourceInfo);

                    // 统计推送成功的数据（统计不到apis 的量）
                    FlowCountDTO flowCountDTO = new FlowCountDTO();
                    flowCountDTO.setInfoId(merchantBaseInfo.getId());
                    flowCountDTO.setChannelCode(memberSourceInfo.getChannelCode());
                    flowCountDTO.setInfoName(merchantBaseInfo.getInfoName());
                    merchantDataPushFlowCountInfoService.updateFlowCount(flowCountDTO);

                    // 推送金额大于20 的时候，更新用户信息，且更新用户缓存信息
                    if (new BigDecimal(20).compareTo(merchantOrderDTO.getPriceAmount()) < 0){

                        MemberBaseInfoDTO memberBaseInfoDTO = new MemberBaseInfoDTO();
                        memberBaseInfoDTO.setUid(memberSourceInfo.getUid());
                        memberBaseInfoDTO.setShowProdTime(LocalDateTime.now().plusDays(3));
                        memberCommonService.updateMemberBaseInfoDTOInfo(memberBaseInfoDTO);
                    }
                }
            });

            return dataPushResult;
        } catch (Exception exception) {
            exception.printStackTrace();
            notifyExceptionService.notifyNoticeInfo("PUSH_TO_MERCHANT_EXEC", "推送给机构异常", JSON.toJSONString(dataMatchOrderItem), exception);
            throw exception;
        }
    }

    /**
     * 推送完成，进行推送的统计与入账
     *
     * @param pushSettleDTO
     */
    @Override
    public void handlePushToData(PushSettleDTO pushSettleDTO, MemberSourceInfo memberSourceInfo) {

        // 账户结算
        if (pushSettleDTO.isSettleFlag()) {

            CountInfoDTO countInfoDTO = new CountInfoDTO(pushSettleDTO.getChannelCode());
            // 修改商户账户余额，添加账户流水
            changeAccountAmount(pushSettleDTO);
            // 统计推送金额
            countInfoDTO.setMerchPushCount(1);

            Integer infoId = pushSettleDTO.getInfoId();
            MerchantBaseInfo baseInfo = merchantBaseInfoMapper.selectById(infoId);

            if (baseInfo != null) {
                String infoType = baseInfo.getInfoType();
                if (StrUtil.equals(infoType, InfoTypeEnum.API.getValue()) || StrUtil.equals(infoType, InfoTypeEnum.CRM.getValue())) {
                    countInfoDTO.setMerchJiGouPushAmount(pushSettleDTO.getSettleAmount());
                }
            }

            countInfoDTO.setMerchPushAmount(pushSettleDTO.getSettleAmount());

            Long uid = memberSourceInfo.getUid();
            String redisKey = StrUtil.format(RedisKeyConstant.MERCHANT_PUSH_MEMBER_KEY, memberSourceInfo.getChannelCode());
            Boolean hasKey = stringRedisTemplate.opsForSet().isMember(redisKey, uid + "");
            if (!hasKey) {
                countInfoDTO.setMerchRealPushCount(1);
            }
            stringRedisTemplate.opsForSet().add(redisKey, uid + "");
            stringRedisTemplate.expire(redisKey, 1L, TimeUnit.DAYS);

            channelCommonService.updateChannelCount(countInfoDTO);
        }

        PushCountDTO pushCountDTO = new PushCountDTO();
        pushCountDTO.setInfoId(pushSettleDTO.getInfoId());
        pushCountDTO.setTaskId(pushSettleDTO.getTaskId());
        pushCountDTO.setInfoType(pushSettleDTO.getInfoType());
        pushCountDTO.setSuccessNumber(pushSettleDTO.isPushFlag() ? 1 : 0);
        pushCountDTO.setSettleNumber(pushSettleDTO.isSettleFlag() ? 1 : 0);
        // 推送数量统计
        merchantPushCountInfoService.savePushResult(pushCountDTO);
    }


    private void changeAccountAmount(PushSettleDTO pushSettleDTO) {
        // 进行记账
        ChangeAmountDTO changeAmountDTO = new ChangeAmountDTO();
        changeAmountDTO.setChangeAmount(BigDecimal.ZERO.subtract(pushSettleDTO.getSettleAmount()));
        changeAmountDTO.setAccountId(pushSettleDTO.getInfoId());
        changeAmountDTO.setAccountName(pushSettleDTO.getInfoName());
        changeAmountDTO.setActionTypeEnum(ActionTypeEnum.XH);
        changeAmountDTO.setAccountTypeEnum(AccountTypeEnum.MERCHANT);
        changeAmountDTO.setBillDateInfo(LocalDate.now().toString());
        changeAmountDTO.setOperatorId("0");
        changeAmountDTO.setOperatorName("system");
        String dataInfo = StrUtil.format("【OrderId】{}【ItemId】{}", pushSettleDTO.getOrderId(), pushSettleDTO.getOrderItemId());
        changeAmountDTO.setDataInfo(dataInfo);
        changeAmountDTO.setRemarkInfo("【pushId】" + pushSettleDTO.getPushPoolId());
        boolean amountHandle = accountHandleService.changeAmountHandle(changeAmountDTO);
    }


}
